#!/usr/bin/env python
# -*- coding: utf-8 -*-

# 程序名称: WiFi历史连接记录查看工具
# 创建日期: 2025-01-10
# 作者信息: Dangks
# 功能描述:
#     1. 查看Windows系统中保存的所有WiFi配置信息
#     2. 显示WiFi名称和对应的密码
#     3. 支持搜索过滤WiFi列表
#     4. 支持复制选中的WiFi信息
#     5. 支持导出WiFi列表到文本文件
#     6. 支持删除过期的WiFi配置


import subprocess
import re
import tkinter as tk
from tkinter import ttk, filedialog
from tkinter import messagebox
import json
import sys
import threading
from datetime import datetime
from utils import center_window, get_icon_path

class WifiHistory:
    def __init__(self, parent=None):
        # 创建窗口
        self.window = tk.Toplevel(parent) if parent else tk.Tk()
        self.window.title("WiFi历史账密信息")
        
        # 设置窗口位置和大小
        center_window(self.window, 700, 500)
        self.window.resizable(True, True)
        self.window.iconbitmap(get_icon_path())
        
        # 如果有父窗口，设置模态
        if parent:
            self.window.transient(parent)
            self.window.grab_set()
        
        # 创建主框架
        main_frame = ttk.Frame(self.window)
        main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)
        
        # 创建顶部工具栏
        toolbar = ttk.Frame(main_frame)
        toolbar.pack(fill=tk.X, pady=(0, 5))
        
        # 创建搜索框
        self.search_var = tk.StringVar()
        self.search_var.trace('w', self.filter_records)
        search_frame = ttk.Frame(toolbar)
        search_frame.pack(side=tk.LEFT, fill=tk.X, expand=True)
        ttk.Label(search_frame, text="搜索WiFi名称:").pack(side=tk.LEFT)
        ttk.Entry(search_frame, textvariable=self.search_var).pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5)
        
        # 状态标签
        self.status_label = ttk.Label(toolbar, text="")
        self.status_label.pack(side=tk.RIGHT)
        
        # 创建表格和按钮
        self.create_treeview(main_frame)
        self.create_buttons(main_frame)
        
        # 检查权限并加载数据
        if self.is_admin():
            self.refresh_wifi_info()
        else:
            messagebox.showerror("错误", "请以管理员身份运行程序!")
            self.window.destroy()
            return
            
        # 仅在独立运行时启动主循环
        if not parent:
            self.window.mainloop()

    def create_treeview(self, parent):
        # 创建带滚动条的表格
        tree_frame = ttk.Frame(parent)
        tree_frame.pack(fill=tk.BOTH, expand=True)
        
        self.tree = ttk.Treeview(tree_frame, columns=("SSID", "密码"), show="headings")
        vsb = ttk.Scrollbar(tree_frame, orient="vertical", command=self.tree.yview)
        hsb = ttk.Scrollbar(tree_frame, orient="horizontal", command=self.tree.xview)
        
        self.tree.configure(yscrollcommand=vsb.set, xscrollcommand=hsb.set)
        self.tree.tag_configure('hidden', foreground='white')  # 初始化隐藏标签样式
        
        # 配置网格布局
        self.tree.grid(column=0, row=0, sticky='nsew')
        vsb.grid(column=1, row=0, sticky='ns')
        hsb.grid(column=0, row=1, sticky='ew')
        
        tree_frame.grid_columnconfigure(0, weight=1)
        tree_frame.grid_rowconfigure(0, weight=1)
        
        # 配置列
        self.tree.heading("SSID", text="WiFi名称", command=lambda: self.sort_treeview("SSID"))
        self.tree.heading("密码", text="密码")
        self.tree.column("SSID", width=200)
        self.tree.column("密码", width=200)

    def create_buttons(self, parent):
        btn_frame = ttk.Frame(parent)
        btn_frame.pack(fill=tk.X, pady=10)
        
        ttk.Button(btn_frame, text="刷新列表", command=self.refresh_wifi_info).pack(side=tk.LEFT, padx=5)
        ttk.Button(btn_frame, text="删除选中", command=self.delete_selected).pack(side=tk.LEFT, padx=5)
        ttk.Button(btn_frame, text="导出列表", command=self.export_list).pack(side=tk.LEFT, padx=5)
        ttk.Button(btn_frame, text="复制选中", command=self.copy_selected).pack(side=tk.LEFT, padx=5)
        ttk.Button(btn_frame, text="关闭窗口", command=self.window.destroy).pack(side=tk.RIGHT, padx=5)

    def is_admin(self):
        try:
            return subprocess.check_output('net session', shell=True, stderr=subprocess.PIPE)
        except:
            return False

    def refresh_wifi_info(self):
        """异步刷新WiFi列表"""
        self.status_label.config(text="正在加载WiFi信息...")
        threading.Thread(target=self._async_load_wifi_info, daemon=True).start()
    
    def _async_load_wifi_info(self):
        try:
            # 使用一次命令获取所有配置信息
            cmd = 'netsh wlan show profiles'
            output = subprocess.check_output(cmd, shell=True).decode('gbk', errors='ignore')
            profiles = re.findall(r"所有用户配置文件\s+:\s+(.*)", output)
            
            if not profiles:
                self.window.after(0, lambda: self.status_label.config(text="未找到WiFi记录"))
                return
                
            # 创建线程池并行获取密码
            wifi_list = []
            threads = []
            lock = threading.Lock()
            
            def get_wifi_password(profile):
                try:
                    cmd = f'netsh wlan show profile name="{profile}" key=clear'
                    result = subprocess.check_output(cmd, shell=True).decode('gbk', errors='ignore')
                    password = re.search(r"关键内容\s+:\s+(.*)", result)
                    if password:
                        with lock:
                            wifi_list.append({
                                "ssid": profile.strip(),
                                "password": password.group(1).strip()
                            })
                            # 更新进度
                            progress = len(wifi_list) / len(profiles) * 100
                            self.window.after(0, lambda: self.status_label.config(
                                text=f"正在加载... {progress:.0f}% ({len(wifi_list)}/{len(profiles)})"
                            ))
                except:
                    pass
            
            # 创建并启动线程
            chunk_size = 5  # 每批处理的数量
            for i in range(0, len(profiles), chunk_size):
                chunk = profiles[i:i + chunk_size]
                for profile in chunk:
                    thread = threading.Thread(target=get_wifi_password, args=(profile,))
                    threads.append(thread)
                    thread.start()
                
                # 等待当前批次完成
                for thread in threads[-chunk_size:]:
                    thread.join()
            
            # 更新UI
            self.window.after(0, self._update_ui, wifi_list)
            
        except Exception as e:
            self.window.after(0, lambda: self.status_label.config(text=f"加载失败: {str(e)}"))

    def _update_ui(self, wifi_list):
        # 清空现有记录
        for item in self.tree.get_children():
            self.tree.delete(item)
            
        if not wifi_list:
            self.status_label.config(text="未找到WiFi记录")
            return
            
        # 按SSID排序并更新表格
        for wifi in sorted(wifi_list, key=lambda x: x["ssid"].lower()):
            self.tree.insert("", tk.END, values=(wifi["ssid"], wifi["password"]))
            
        self.status_label.config(text=f"已加载 {len(wifi_list)} 个WiFi记录")


    def filter_records(self, *args):
        """实现搜索过滤"""
        search_term = self.search_var.get().lower()
        visible_count = 0
        
        try:
            # 获取所有项目
            all_items = self.tree.get_children()
            self.tree.selection_remove(*all_items)  # 清除选中状态
            
            if not search_term:
                # 如果搜索词为空，显示所有项目
                for item in all_items:
                    self.tree.item(item, tags=())
                self.status_label.config(text=f"共 {len(all_items)} 条记录")
                return
            
            # 存储匹配和不匹配的项目
            matched_items = []
            unmatched_items = []
            
            # 遍历并分类
            for item in all_items:
                values = self.tree.item(item)['values']
                if not values:
                    continue
                    
                ssid = str(values[0]).lower()
                if search_term in ssid:
                    matched_items.append(item)
                    visible_count += 1
                else:
                    unmatched_items.append(item)
            
            # 重新排序：先删除所有项，然后按顺序重新插入
            for item in all_items:
                self.tree.detach(item)
                
            # 先插入匹配项
            for item in matched_items:
                self.tree.reattach(item, '', 0)  # 插入到顶部
                self.tree.item(item, tags=())
                
            # 再插入不匹配项
            for item in unmatched_items:
                self.tree.reattach(item, '', 'end')  # 插入到底部
                self.tree.item(item, tags=('hidden',))
            
            # 如果有匹配项，确保第一个匹配项可见
            if matched_items:
                self.tree.see(matched_items[0])
                self.tree.selection_add(matched_items[0])  # 选中第一个匹配项
            
            # 更新状态显示
            self.status_label.config(text=f"找到 {visible_count} 条匹配记录")
                    
        except Exception as e:
            self.status_label.config(text=f"搜索出错: {str(e)}")
            messagebox.showerror("错误", f"搜索过程中发生错误: {str(e)}")

    def sort_treeview(self, col):
        """排序表格"""
        l = [(self.tree.set(k, col), k) for k in self.tree.get_children("")]
        l.sort(key=lambda x: x[0].lower())
        for index, (_, k) in enumerate(l):
            self.tree.move(k, "", index)

    def copy_selected(self):
        """复制选中项，支持多选"""
        selection = self.tree.selection()
        if not selection:
            messagebox.showwarning("提示", "请先选择要复制的记录")
            return
            
        # 构建复制内容
        copy_text = []
        for item in selection:
            values = self.tree.item(item)['values']
            copy_text.append(f"WiFi名称: {values[0]}\n密码: {values[1]}\n")
        
        # 合并内容，每条记录间添加分隔线
        text = "\n".join(copy_text)
        
        # 复制到剪贴板
        self.window.clipboard_clear()
        self.window.clipboard_append(text)
        
        # 更新状态显示
        self.status_label.config(text=f"已复制 {len(selection)} 条记录")
        messagebox.showinfo("成功", f"已复制 {len(selection)} 条记录到剪贴板")

    def export_list(self):
        """导出WiFi列表"""
        # 获取所有可见项（非隐藏项）
        visible_items = [item for item in self.tree.get_children() 
                        if 'hidden' not in self.tree.item(item)['tags']]
        
        if not visible_items:
            messagebox.showwarning("提示", "没有可导出的WiFi记录")
            return
            
        # 确认是否只导出搜索结果
        export_all = True
        if self.search_var.get():  # 如果有搜索内容
            if messagebox.askyesno("导出确认", 
                                "是否只导出搜索结果？\n选择\"否\"将导出全部记录"):
                export_all = False
        
        # 确定要导出的项目
        items_to_export = self.tree.get_children() if export_all else visible_items
        
        filename = f"wifi_history_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt"
        filepath = filedialog.asksaveasfilename(
            defaultextension=".txt",
            filetypes=[("文本文件", "*.txt"), ("所有文件", "*.*")],
            initialfile=filename
        )
        
        if not filepath:
            return
            
        try:
            with open(filepath, "w", encoding="utf-8") as f:
                f.write("WiFi历史连接记录\n")
                f.write("="*50 + "\n\n")
                f.write("导出时间: " + datetime.now().strftime("%Y-%m-%d %H:%M:%S") + "\n")
                f.write("导出方式: " + ("全部记录" if export_all else "搜索结果") + "\n\n")
                
                for item in items_to_export:
                    values = self.tree.item(item)['values']
                    f.write(f"WiFi名称: {values[0]}\n")
                    f.write(f"WiFi密码: {values[1]}\n\n")
                    
            messagebox.showinfo("成功", f"已导出到:\n{filepath}")
        except Exception as e:
            messagebox.showerror("错误", f"导出失败: {str(e)}")

    def delete_selected(self):
        """删除选中的WiFi配置"""
        selection = self.tree.selection()
        if not selection:
            messagebox.showwarning("提示", "请先选择要删除的记录")
            return
            
        # 获取选中项的WiFi名称
        wifi_names = []
        for item in selection:
            values = self.tree.item(item)['values']
            wifi_names.append(values[0])
        
        # 确认删除
        if not messagebox.askyesno("删除确认", 
            f"确定要删除选中的 {len(selection)} 个WiFi配置吗？\n"
            "注意：删除后将无法恢复，需要重新输入密码才能连接这些WiFi。\n\n"
            f"要删除的WiFi:\n{chr(10).join(wifi_names)}"):
            return
        
        # 执行删除
        delete_failed = []
        delete_success = []
        
        for wifi_name in wifi_names:
            try:
                cmd = f'netsh wlan delete profile name="{wifi_name}"'
                subprocess.check_output(cmd, shell=True)
                delete_success.append(wifi_name)
            except:
                delete_failed.append(wifi_name)
        
        # 删除树形控件中的项目
        for item in selection:
            self.tree.delete(item)
        
        # 更新状态
        success_count = len(delete_success)
        failed_count = len(delete_failed)
        
        status_msg = f"成功删除 {success_count} 个WiFi配置"
        if failed_count > 0:
            status_msg += f"，{failed_count} 个删除失败"
        
        self.status_label.config(text=status_msg)
        
        # 如果有失败的项目，显示详细信息
        if delete_failed:
            messagebox.showwarning("删除结果", 
                f"以下WiFi删除失败:\n{chr(10).join(delete_failed)}\n\n"
                "可能是因为权限不足或该WiFi配置已不存在。")
        else:
            messagebox.showinfo("删除成功", 
                f"已成功删除 {success_count} 个WiFi配置")

if __name__ == "__main__":
    WifiHistory()